/**
 * Copyright (c) 2018-2022, NXOS Development Team
 * SPDX-License-Identifier: Apache-2.0
 * 
 * Copyright(c) 2007-2022 Jianjun Jiang <8192542@qq.com>
 *          Official site: http://xboot.org
 *          Mobile phone: +86-18665388956
 *          QQ: 8192542
 * 
 * Contains: nxos file system.
 * 
 * Change Logs:
 * Date           Author            Notes
 * 2022-3-26      JasonHu           Port from xboot
 */

#ifndef __NXOS_FILE_SYSTEM__
#define __NXOS_FILE_SYSTEM__

#include <nxos_mini.h>
#include <base/mutex.h>
#include <base/atomic.h>
#include <base/list.h>

#ifdef CONFIG_NX_FILE_MAX_PATH 
#define NX_FILE_MAX_PATH CONFIG_NX_FILE_MAX_PATH
#else
#define NX_FILE_MAX_PATH		    (1024)
#endif

#ifdef CONFIG_NX_FILE_MAX_NAME
#define NX_FILE_MAX_NAME CONFIG_NX_FILE_MAX_NAME
#else
#define NX_FILE_MAX_NAME		    (256)
#endif

#ifdef CONFIG_NX_FILE_MAX_FD
#define NX_FILE_MAX_FD CONFIG_NX_FILE_MAX_FD
#else
#define NX_FILE_MAX_FD		    (256)
#endif

#ifdef CONFIG_NX_FILE_NODE_HASH_SIZE
#define NX_FILE_NODE_HASH_SIZE CONFIG_NX_FILE_NODE_HASH_SIZE
#else
#define NX_FILE_NODE_HASH_SIZE   (256)
#endif

#define NX_FILE_RDONLY			(1 << 0)
#define NX_FILE_WRONLY			(1 << 1)
#define NX_FILE_RDWR			(NX_FILE_RDONLY | NX_FILE_WRONLY)
#define NX_FILE_ACCMODE		    (NX_FILE_RDWR)

#define NX_FILE_CREAT			(1 << 8)
#define NX_FILE_EXCL			(1 << 9)
#define NX_FILE_TRUNC			(1 << 11)
#define NX_FILE_APPEND			(1 << 12)

#define NX_FILE_MODE_EXEC			(1 << 6)
#define NX_FILE_MODE_WRITE			(1 << 7)
#define NX_FILE_MODE_READ			(1 << 8)
#define NX_FILE_MODE_MASK			(NX_FILE_MODE_READ | NX_FILE_MODE_WRITE | NX_FILE_MODE_EXEC)

#define	NX_FILE_TYPE_DIR			(1 << 16)
#define	NX_FILE_TYPE_REG			(1 << 19)
#define	NX_FILE_TYPE_MASK			(NX_FILE_TYPE_DIR | NX_FILE_TYPE_REG)

#define NX_FILE_IS_DIR(m)		    ((m) & NX_FILE_TYPE_DIR )
#define NX_FILE_IS_REG(m)		    ((m) & NX_FILE_TYPE_REG )

#define	NX_FILE_READ_OK				(1 << 2)
#define NX_FILE_WRITE_OK			(1 << 1)
#define NX_FILE_EXEC_OK				(1 << 0)

#define NX_FILE_SEEK_SET		    (0)
#define NX_FILE_SEEK_CUR		    (1)
#define NX_FILE_SEEK_END		    (2)

struct NX_FileStatInfo;
struct NX_Dirent;
struct NX_FileNode;
struct NX_MountDesc;
struct NX_FileSystem;

typedef struct NX_FileStatInfo
{
	NX_Size size;
	NX_U32 mode;
	NX_U32 ctime;
	NX_U32 atime;
	NX_U32 mtime;
} NX_FileStatInfo;

enum NX_DirentType
{
	NX_DIR_TYPE_UNK,
	NX_DIR_TYPE_DIR,
	NX_DIR_TYPE_REG,
};

typedef struct NX_Dirent
{
	NX_Offset off;
	NX_U32 reclen;
	enum NX_DirentType type;
	char name[NX_FILE_MAX_NAME];
} NX_Dirent;

enum NX_FileNodeFlag
{
	NX_FILE_NODE_FLAG_NONE,
	NX_FILE_NODE_FLAG_ROOT,
};

enum NX_FileNodeType
{
	NX_FILE_NODE_TYPE_UNK,
	NX_FILE_NODE_TYPE_DIR,
	NX_FILE_NODE_TYPE_REG,
};
/**
 * todo: 添加address_space概念，优化文件读写速度。
*/
typedef struct NX_FileNode
{
	NX_List link;
	struct NX_MountDesc * mount;
	NX_Atomic refcnt;
	char path[NX_FILE_MAX_PATH];
	enum NX_FileNodeFlag flags;
	enum NX_FileNodeType type;
	NX_Mutex lock;
	NX_Mutex rdlock;
	NX_Mutex wrlock;
	NX_U32 ctime;
	NX_U32 atime;
	NX_U32 mtime;
	NX_U32 mode;
	NX_Size size;
	void * data;
} NX_FileNode;

typedef struct NX_FileDesc
{
	NX_Mutex lock;
	struct NX_FileNode * node;
	NX_Offset offset;
	NX_U32 flags;
} NX_FileDesc;

typedef struct NX_FileTable
{
	struct NX_FileDesc file[NX_FILE_MAX_FD];
    NX_Mutex file_lock;
} NX_FileTable;

void NX_FileTableInit(NX_FileTable *ft);
NX_FileTable *NX_FileTableGetDefault(void);

enum
{
	NX_MOUNT_RW	    = (0x0 << 0),
	NX_MOUNT_RO	    = (0x1 << 0),
	NX_MOUNT_MASK	= (0x1 << 0),
};

typedef struct NX_MountDesc
{
	NX_List link;
	struct NX_FileSystem * fs;
	void * dev;
	char path[NX_FILE_MAX_PATH];
	NX_U32 flags;
	NX_Atomic refcnt;
	struct NX_FileNode * root;
	struct NX_FileNode * covered;
	NX_Mutex lock;
	void * data;
} NX_MountDesc;

typedef struct NX_FileSystem
{
	NX_List list;
	const char * name;

	NX_Error (*mount)(NX_MountDesc *, const char *);
	NX_Error (*unmount)(NX_MountDesc *);
	NX_Error (*mountSync)(NX_MountDesc *);
	NX_Error (*getNode)(NX_MountDesc *, NX_FileNode *);
	NX_Error (*putNode)(NX_MountDesc *, NX_FileNode *);

	NX_U64 (*read)(NX_FileNode *, NX_I64, void *, NX_U64, NX_Error *outErr);
	NX_U64 (*write)(NX_FileNode *, NX_I64, void *, NX_U64, NX_Error *outErr);
    NX_Error (*ioctl)(NX_FileNode *, NX_U32, void *);
	NX_Error (*truncate)(NX_FileNode *, NX_I64);
	NX_Error (*sync)(NX_FileNode *);
	NX_Error (*readDir)(NX_FileNode *, NX_I64, NX_Dirent *);
	NX_Error (*lookup)(NX_FileNode *, const char *, NX_FileNode *);
	NX_Error (*create)(NX_FileNode *, const char *, NX_U32);
	NX_Error (*delete)(NX_FileNode *, NX_FileNode *, const char *);
	NX_Error (*rename)(NX_FileNode *, const char *, NX_FileNode *, NX_FileNode *, const char *);
	NX_Error (*createDir)(NX_FileNode *, const char *, NX_U32);
	NX_Error (*deleteDir)(NX_FileNode *, NX_FileNode *, const char *);
	NX_Error (*setMode)(NX_FileNode *, NX_U32);
} NX_FileSystem;

NX_FileSystem * NX_FileSystemSearch(const char * name);
NX_Error NX_FileSystemRegister(NX_FileSystem * fs);
NX_Error NX_FileSystemUnregister(NX_FileSystem * fs);
NX_MountDesc * NX_MountGetByIndex(int index);
int NX_MountGetCount(void);
NX_Error NX_PathBuildAbs(const char * path, char * absPath);

/* user interface */
NX_Error NX_FileSystemMount(const char * dev, const char * path, const char * fsname, NX_U32 flags);
NX_Error NX_FileSystemUnmount(const char * path);
NX_Error NX_FileSystemSync(void);
int NX_FileOpen(const char * path, NX_U32 flags, NX_U32 mode, NX_Error *outErr);
NX_Error NX_FileClose(int fd);
NX_U64 NX_FileRead(int fd, void * buf, NX_U64 len, NX_Error *outErr);
NX_U64 NX_FileWrite(int fd, void * buf, NX_U64 len, NX_Error *outErr);
NX_Error NX_FileIoctl(int fd, NX_U32 cmd, void *arg);
NX_Offset NX_FileSetPointer(int fd, NX_Offset off, int whence, NX_Error *outErr);
NX_Error NX_FileSync(int fd);
NX_Error NX_FileSetMode(int fd, NX_U32 mode);
NX_Error NX_FileGetStat(int fd, NX_FileStatInfo * st);
int NX_DirOpen(const char * name, NX_Error *outErr);
NX_Error NX_DirClose(int fd);
NX_Error NX_DirRead(int fd, NX_Dirent * dir);
NX_Error NX_DirResetPointer(int fd);
NX_Error NX_DirCreate(const char * path, NX_U32 mode);
NX_Error NX_DirDelete(const char * path);
NX_Error NX_FileRename(const char * src, const char * dst);
NX_Error NX_FileDelete(const char * path);
NX_Error NX_FileAccess(const char * path, NX_U32 mode);
NX_Error NX_FileSetModeToPath(const char * path, NX_U32 mode);
NX_Error NX_FileGetStatFromPath(const char * path, NX_FileStatInfo * st);

#endif /* __NXOS_FILE_SYSTEM__ */
